import {
    SelectedState,
    EditState,
    Column,
    DataSource,
} from './type';
import { deepCopy } from "./util"
import { watch, onMounted, onBeforeUnmount } from "vue"

interface SaveOptions {
    columns: Column[]
    dataSource: DataSource[]
    selectedState: SelectedState
    editState: EditState
}


export default class {
    private storeIndex: number = 0
    private storeData: SaveOptions[] = []
    private limitCount: number = 30
    private autoSaveTimer: any
    private freezeAutoSaveTimer: any
    private stopWatchHandeler: any
    private config: {
        beforeRedoUndo?: () => Promise<void>
        redoUndoCallback: Function
    }

    constructor(config: {
        beforeRedoUndo?: () => Promise<void>
        redoUndoCallback: Function
    }){
        this.config = config
        const keydownHandel = async () => {
            // CTRL + Z
            if ((event?.ctrlKey || event?.metaKey) && event?.keyCode === 90) {
                event.preventDefault();
                this.undo();
            }
            // CTRL + Y
            if ((event?.ctrlKey || event?.metaKey) && event?.keyCode === 89) {
                event.preventDefault();
                this.redo()
            }
        }
        onMounted(() => {
            document.addEventListener('keydown', keydownHandel);
        });
        onBeforeUnmount(() => {
            this.destory();
            document.removeEventListener('keydown', keydownHandel);
        });
    }

    /**
     * 恢复
     * @returns 
     */
    async redo(){
        if(!this.can_redo()) return;

        this.startFreezeAutoSave();
        this.storeIndex = this.storeIndex + 1;
        const params = deepCopy(this.storeData[this.storeIndex])

        await this.config?.beforeRedoUndo?.()
        params && this.config.redoUndoCallback(params)
        // console.log("数据重做了", this.storeData, this.storeIndex)
    }
    can_redo(){
        return this.storeIndex < this.storeData.length - 1;
    }

    /**
     * 撤销
     * @returns 
     */
    async undo(){
        if(!this.can_undo()) return;

        this.startFreezeAutoSave();
        this.storeIndex = this.storeIndex - 1;
        const params = deepCopy(this.storeData[this.storeIndex])

        await this.config?.beforeRedoUndo?.()
        params && this.config.redoUndoCallback(params)
        // console.log("数据撤销了", this.storeData, this.storeIndex)
    }
    can_undo(){
        return this.storeIndex > 0
    }

    /**
     * 保存快照数据
     * @param option 快照数据
     * @param callback 保存成功回调
     * @returns 
     */
    save(option: SaveOptions, callback?: () => void){
        if (JSON.stringify(option) === JSON.stringify(this.storeData.at(-1))) {
            this.storeIndex = this.storeData.length - 1;
            return
        };

        const DATA = deepCopy(option)
        this.storeData.splice(this.storeIndex + 1, this.limitCount * 2, DATA)
        this.storeIndex++;

        if(this.storeData.length > this.limitCount){
            this.storeData.shift()
        }

        if(typeof callback === 'function') callback()

        // console.log("数据快照更新了", this.storeData, this.storeIndex)
    }

    /**
     * 自动记录历史快照
     * @param getter () => Record
     * @param interval 探测到变化，记录getter返回值的延迟时间。
     */
    autoSaveChange(getter: any, interval: number = 300){
        this.stopWatchHandeler = watch(getter, (data: SaveOptions) => {
            if(this.autoSaveTimer || this.freezeAutoSaveTimer) return;

            this.save(data)

            this.autoSaveTimer = setTimeout(() => {
                this.clearAutoSaveTimer()
            }, interval)

        },{
            deep: true,
        })
    }

    /**
     * 销毁历史记录
     */
    destory(){
        this.stopWatchHandeler?.();
        this.storeIndex = 0;
        this.storeData = []
        this.clearAutoSaveTimer()
        this.clearFreezeAutoSave()
    }

    getLength(){
        return this.storeData.length;
    }

    private startFreezeAutoSave(){
        this.clearFreezeAutoSave()
        this.freezeAutoSaveTimer = setTimeout(() => {
            this.clearFreezeAutoSave()
        }, 300)
    }
    private clearFreezeAutoSave(){
        clearTimeout(this.freezeAutoSaveTimer)
        this.freezeAutoSaveTimer = null
    }
    private clearAutoSaveTimer(){
        clearTimeout(this.autoSaveTimer)
        this.autoSaveTimer = null
    }
}